import { select } from 'd3-selection'
import { hasChild } from './index'

/**
 * 获取指定主题下的最后一个子主题列表
 * @param {*} node
 * @param {*} posXList
 */
export function maxChildRefPosX (node, posXList = []) {
  if (!hasChild(node)) {
    posXList.push(node)
  } else {
    for (let i = 0; i < node.children.length; i++) {
      maxChildRefPosX(node.children[i], posXList)
    }
  }
}

export function maxChildRefPosY (node, posYList = []) {
  if (!hasChild(node)) {
    posYList.push(node)
  } else {
    for (let i = 0; i < node.children.length; i++) {
      maxChildRefPosY(node.children[i], posYList)
    }
  }
}

/**
 * 设置指定主题下最右侧极大值X坐标
 * @param {*} posXList
 * @param {*} id
 */
export function setMaxSummaryPosX (posXList, id) {
  for (let i = 0; i < posXList.length; i++) {
    const maxPosX = posXList[i].x + posXList[i].width + (posXList[i].data.expand ? 0 : 22)
    if (posXList[i].data._id === id) {
      posXList[i].maxPosX = maxPosX
    } else {
      posXList[i].maxPosX = getTargetMaxPosX(posXList[i], maxPosX, id)
    }
  }
}

export function setMaxSummaryPosY (posYList, id) {
  for (let i = 0; i < posYList.length; i++) {
    const maxPosY = posYList[i].y + posYList[i].height + (posYList[i].data.expand ? 0 : 22)
    if (posYList[i].data._id === id) {
      posYList[i].maxPosY = maxPosY
    } else {
      posYList[i].maxPosY = getTargetMaxPosY(posYList[i], maxPosY, id)
    }
  }
}

/**
 *
 * @param {*} node
 * @param {*} maxPosX
 * @param {*} id
 * @returns
 */
export function getTargetMaxPosX (node, maxPosX, id) {
  const targetSummarys = node.data.targetSummarys
  const summaryWidth = targetSummarys?.length ? Math.max(...targetSummarys.map(o => o.summaryWidth)) : 0
  maxPosX += (summaryWidth ? summaryWidth + 42 : 0)
  if (node.parent && node.parent.data._id !== id) {
    maxPosX = getTargetMaxPosX(node.parent, maxPosX, id)
  }
  return maxPosX
}

function getTargetMaxPosY (node, maxPosY, id) {
  const targetSummarys = node.data.targetSummarys
  const summaryHeight = targetSummarys?.length ? Math.max(...targetSummarys.map(o => o.summaryHeight)) : 0
  maxPosY += (summaryHeight ? summaryHeight + 42 : 0)
  if (node.parent && node.parent.data._id !== id) {
    maxPosY = getTargetMaxPosY(node.parent, maxPosY, id)
  }
  return maxPosY
}

/**
 * 设置指定主题下最左端极小值X坐标
 * @param {*} posXList
 * @param {*} id
 */
export function setMinSummaryPosX (posXList, id) {
  for (let i = 0; i < posXList.length; i++) {
    const minPosX = posXList[i].x - (posXList[i].data.expand ? 0 : 22)
    if (posXList[i].data._id === id) {
      posXList[i].minPosX = minPosX
    } else {
      posXList[i].minPosX = getTargetMinPosX(posXList[i], minPosX, id)
    }
  }
}

export function setMinSummaryPosY (posYList, id) {
  for (let i = 0; i < posYList.length; i++) {
    const minPosY = posYList[i].y - (posYList[i].data.expand ? 0 : 22)
    if (posYList[i].data._id === id) {
      posYList[i].minPosY = minPosY
    } else {
      posYList[i].minPosY = getTargetMinPosY(posYList[i], minPosY, id)
    }
  }
}

/**
 *
 * @param {*} node
 * @param {*} minPosX
 * @param {*} id
 * @returns
 */
export function getTargetMinPosX (node, minPosX, id) {
  const targetSummarys = node.data.targetSummarys
  const summaryWidth = targetSummarys?.length ? Math.max(...targetSummarys.map(o => o.summaryWidth)) : 0
  minPosX -= (summaryWidth ? summaryWidth + 42 : 0)
  if (node.parent && node.parent.data._id !== id) {
    minPosX = getTargetMinPosX(node.parent, minPosX, id)
  }
  return minPosX
}

function getTargetMinPosY (node, minPosY, id) {
  const targetSummarys = node.data.targetSummarys
  const summaryHeight = targetSummarys?.length ? Math.max(...targetSummarys.map(o => o.summaryHeight)) : 0
  minPosY -= (summaryHeight ? summaryHeight + 42 : 0)
  if (node.parent && node.parent.data._id !== id) {
    minPosY = getTargetMinPosY(node.parent, minPosY, id)
  }
  return minPosY
}

/**
 * 获取当前节点包括字节点四个顶点坐标
 * @param {*} node
 * @param {*} isSummary 是否为计算概要的包围长宽高数据
 * @returns
 */
export function getXmindSummaryPos (node) {
  const direction = node.direction
  const posXList = []
  maxChildRefPosX(node, posXList)
  direction === 'right' ? setMaxSummaryPosX(posXList, node.data._id) : setMinSummaryPosX(posXList, node.data._id)
  const nodeSortMaxX = direction === 'right'
    ? posXList.sort((a, b) => a.maxPosX - b.maxPosX)
    : node.descendants().sort((a, b) => (a.x + a.width) - (b.x + b.width))
  const nodeSortMinX = direction === 'right'
    ? node.descendants().sort((a, b) => a.x - b.x)
    : posXList.sort((a, b) => a.minPosX - b.minPosX)

  const nodeSortMinY = node.descendants().sort((a, b) => {
    return a.y - b.y
  })
  const nodeSortMaxY = node.descendants().sort((a, b) => (a.y + a.height) - (b.y + b.height))
  const minXNode = nodeSortMinX[0]
  const maxXNode = nodeSortMaxX[nodeSortMaxX.length - 1]
  const minYNode = nodeSortMinY[0]
  const maxYNode = nodeSortMaxY[nodeSortMaxY.length - 1]
  const minX = direction === 'right' ? minXNode.x : minXNode.minPosX - 16
  const maxX = direction === 'right' ? maxXNode.maxPosX + 16 : maxXNode.x + maxXNode.width
  const minY = minYNode.y
  const maxY = maxYNode.y + maxYNode.height
  return {
    minX,
    maxX,
    minY,
    maxY
  }
}

export function getVerticalXmindSummaryPos (node) {
  const direction = node.direction
  const posYList = []
  maxChildRefPosY(node, posYList)
  direction === 'bottom' ? setMaxSummaryPosY(posYList, node.data._id) : setMinSummaryPosY(posYList, node.data._id)
  const nodeSortMaxY = direction === 'bottom'
    ? posYList.sort((a, b) => a.maxPosY - b.maxPosY)
    : node.descendants().sort((a, b) => (a.y + a.height) - (b.y + b.height))
  const nodeSortMinY = direction === 'bottom'
    ? node.descendants().sort((a, b) => a.y - b.y)
    : posYList.sort((a, b) => a.minPosY - b.minPosY)
  const nodeSortMinX = node.descendants().sort((a, b) => a.x - b.x)
  const nodeSortMaxX = node.descendants().sort((a, b) => (a.x + a.width) - (b.x + b.width))
  const minYNode = nodeSortMinY[0]
  const maxYNode = nodeSortMaxY[nodeSortMaxY.length - 1]
  const minXNode = nodeSortMinX[0]
  const maxXNode = nodeSortMaxX[nodeSortMaxX.length - 1]
  const minY = direction === 'bottom' ? minYNode.y : minYNode.minPosY - 16
  const maxY = direction === 'bottom' ? maxYNode.maxPosY + 16 : maxYNode.y + maxYNode.height
  const minX = minXNode.x
  const maxX = maxXNode.x + maxXNode.width
  return {
    minX,
    maxX,
    minY,
    maxY
  }
}

/**
 * 外框文字描述绘制获取Y轴最小值
 * @param {*} node
 * @returns
 */
export function getOutBorderMinY (node) {
  const descendants = node.descendants()
  const cache = [node]
  descendants.forEach(n => {
    if (hasChild(n)) {
      cache.push(n.children[0])
    }
  })
  for (let i = cache.length - 1; i >= 0; i--) {
    if (i === cache.length - 1) {
      cache[i].newMinY = cache[i].y
    } else {
      cache[i].newMinY = cache[i + 1].newMinY - (cache[i + 1].data.outBorder?.height || 0)
    }
  }

  return cache[0].newMinY
}

/**
 * 根据关联连线的源和目标计算连线的起始点结束点以及三次贝塞尔曲线的两个控制点
 * @param {*} source
 * @param {*} target
 */
export function getNodeRelationPathPoints (source, target, lineShape) {
  const { id: sourceId, point: startPoint, controller: startController } = source
  const { id: targetId, point: endPoint, controller: endController } = target
  const sourceRect = select(`#${sourceId}`)?.datum()
  const targetRect = select(`#${targetId}`)?.datum()
  const start = { x: startPoint.x + sourceRect.x, y: startPoint.y + sourceRect.y }
  const end = { x: endPoint.x + targetRect.x, y: endPoint.y + targetRect.y }
  const c1 = { x: start.x + startController.x, y: start.y + startController.y }
  const c2 = { x: end.x + endController.x, y: end.y + endController.y }

  if (lineShape === 'zigzag') {
    // 如果两个控制点的x坐标和两个端点的x轴坐标都相同的话则认为是水平方向
    const isHorizontal = c1.x === start.x && c2.x === end.x
    if (isHorizontal) {
      c2.y = c1.y
    } else {
      c2.x = c1.x
    }
  }
  return {
    start,
    end,
    c1,
    c2
  }
}

export function setRootEdgeSourceGap (data) {
  const rootEdges = data.filter(d => d.source.depth === 0)
  const len = rootEdges.length
  const splitLen = Math.floor(len / 2)
  const percentage = 100 / splitLen * 0.75
  for (let i = 0; i < rootEdges.length; i++) {
    if (i < splitLen) {
      rootEdges[i].target.gapLen = i * percentage
    } else {
      rootEdges[i].target.gapLen = (i - splitLen) * percentage
    }
  }
}
